# -*- coding: utf-8 -*-
# @Author   : zxc19
# @Time     : 2023/7/6 19:21
# @FileName : conftest.py
# @Desc     : 请输入功能模块描述
import os
from typing import List, Generator, Any, Dict

import allure
import pytest
from loguru import logger
from playwright.sync_api import BrowserContext, Page, Browser, Error
from pytest_playwright.pytest_playwright import _build_artifact_test_folder
from slugify import slugify

from config import settings


@pytest.fixture(scope="session")
def browser_type_launch_args(browser_type_launch_args):
    """
    浏览器类型参数配置
    参考链接: https://playwright.dev/python/docs/api/class-browsertype#browser-type-launch
    :param browser_type_launch_args:
    :return:
    """
    return {
        **browser_type_launch_args,
        "headless": False,
        "slow_mo": 0,
        "args": [
            '--start-maximized',  # 浏览器窗口最大化,需要和new_context的no_viewport配合使用
        ]
    }


@pytest.fixture(scope="session")
def browser_context_args(browser_context_args):
    """
    浏览器上下文参数配置
    参考链接: https://playwright.dev/python/docs/api/class-apirequest
    :param browser_context_args:
    :return:
    """
    # 设置base_url到全局
    if browser_context_args.get('base_url', None):
        settings.BASE_URL = browser_context_args.get('base_url')
    return {
        **browser_context_args,
        "ignore_https_errors": True,
        'no_viewport': True,
        # "video_size": {
        #     "width": 1920,
        #     "height": 1080
        # },
        "record_video_size": {
            "width": 1920,
            "height": 1080
        }
    }


# @pytest.fixture(scope="session")
# def context(
#         browser_type: BrowserType,
#         browser_type_launch_args: Dict,
#         browser_context_args: Dict
# ):
#     context = browser_type.launch_persistent_context("./foobar", **{
#         **browser_type_launch_args,
#         **browser_context_args,
#         "locale": "de-DE",
#     })
#     yield context
#     context.close()


@pytest.fixture(scope='session')
def context(
        browser: Browser,
        browser_context_args: Dict,
        pytestconfig: Any,
        request: pytest.FixtureRequest,
) -> Generator[BrowserContext, None, None]:
    """
    浏览器上下文对象，会话级
    处理掉保存trace和截屏
    :param browser: 浏览器对象
    :param browser_context_args: 浏览器上下文参数配置
    :param pytestconfig: pytest配置
    :param request: 请求对象
    :return:
    """
    pages: List[Page] = []
    context = browser.new_context(**browser_context_args)
    context.on("page", lambda page: pages.append(page))
    yield context
    # 判断是否失败
    failed = request.node.rep_call.failed if hasattr(request.node, "rep_call") else True
    context.close()
    # 视频录制
    video_option = pytestconfig.getoption("--video")
    preserve_video = video_option == "on" or (
            failed and video_option == "retain-on-failure"
    )
    if preserve_video:
        for page in pages:
            video = page.video
            if not video:
                continue
            try:
                video_path = video.path()
                file_name = os.path.basename(video_path)
                filepath = _build_artifact_test_folder(pytestconfig, request, file_name)
                video.save_as(
                    path=settings.BASE_DIR.joinpath(filepath)
                )
            except Exception as e:
                # Silent catch empty videos.
                logger.warning(f'保存视频失败==>{e}')
                pass


@pytest.fixture(scope='session')
def page(context: BrowserContext) -> Generator[Page, None, None]:
    """
    页面对象
    :param context: 浏览器上下文对象
    :return:
    """
    page = context.new_page()
    yield page


@pytest.fixture(scope='function', autouse=True)
def tracing_screenshot_fixture(
        context,
        pytestconfig: Any,
        request: pytest.FixtureRequest

):
    """
    用例跟踪器和截图
    :param context:
    :param pytestconfig:
    :param request:
    :return:
    """
    pages: List[Page] = context.pages
    # 追踪器
    tracing_option = pytestconfig.getoption("--tracing")
    capture_trace = tracing_option in ["on", "retain-on-failure"]
    if capture_trace:
        context.tracing.start(
            title=slugify(request.node.nodeid),
            screenshots=settings.TRACE_SCREENSHOTS,
            snapshots=settings.TRACE_SNAPSHOTS,
            sources=settings.TRACE_SOURCES,
        )
    yield context

    # 判断是否失败
    failed = request.node.rep_call.failed if hasattr(request.node, "rep_call") else True

    # 追踪器
    if capture_trace:
        retain_trace = tracing_option == "on" or (
                failed and tracing_option == "retain-on-failure"
        )
        if retain_trace:
            trace_path = _build_artifact_test_folder(pytestconfig, request, "trace.zip")
            context.tracing.stop(
                path=settings.BASE_DIR.joinpath(trace_path) if settings.SCREENSHOT_AND_TRACE_SAVE_IN_LOCAL else None)
            # 把截图放入allure报告，记录在teardown的context中
            allure.attach.file(trace_path, name=f"{request.node.name}")
        else:
            context.tracing.stop()

    # 截屏
    screenshot_option = pytestconfig.getoption("--screenshot")
    capture_screenshot = screenshot_option == "on" or (
            failed and screenshot_option == "only-on-failure"
    )
    if capture_screenshot:
        for index, page in enumerate(pages):
            human_readable_status = "failed" if failed else "finished"
            screenshot_path = _build_artifact_test_folder(
                pytestconfig, request, f"test-{human_readable_status}-{index + 1}.png"
            )
            try:
                page.screenshot(timeout=5000,
                                path=settings.BASE_DIR.joinpath(
                                    screenshot_path) if settings.SCREENSHOT_AND_TRACE_SAVE_IN_LOCAL else None)
                # 把截图放入allure报告，记录在teardown的context中
                allure.attach.file(screenshot_path, name=f"{request.node.name}-{human_readable_status}-{index + 1}",
                                   attachment_type=allure.attachment_type.PNG)
            except Error:
                pass
